﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ElfTyping.Animations;
using Microsoft.Xna.Framework;
using ElfTyping.General;
using ElfTyping.Cards;

namespace ElfTyping.States.CampState
{
    public class CampState : State
    {
        const float TotalMenuAnimationTime = .66f;

        Animation BackgroundAnimation = new Animation(@"Textures\CampState\Camp_Background_4_3");
        Rectangle BackgroundRectangle = new Rectangle(0, 0, 800, 600);

        Animation ButtonAnimation = new Animation(@"Textures\Text_Window_CT", new Rectangle(8, 184, 255, 79));
        Animation SelectedButtonAnimation = new Animation(@"Textures\Text_Window_CT", new Rectangle(8, 360, 255, 79));
        Animation InactiveButtonAnimation = new Animation(@"Textures\Text_Window_CT", new Rectangle(8, 536, 255, 79));

        FireEmblemPortraitAnimation SorenAnimation = new SorenPortrait(true);
        Point SorenBottomLeft = FireEmblemPortraitAnimation.BigPortraitRightPosition;

        Rectangle[] buttons = {
            new Rectangle(50, 35, 204, 63),
            new Rectangle(50, 110, 204, 63),
            new Rectangle(50, 185, 204, 63),
            new Rectangle(50, 260, 204, 63),
            new Rectangle(50, 335, 204, 63)
        };

        Stack<MenuItem[]> MenuStack;        
        MenuItem[] CurrentItems { get { return MenuStack.Peek(); } }
        Stack<int> SelectedIndexStack;
        int SelectedItemIndex;
        MenuItem SelectedItem { get { return CurrentItems[SelectedItemIndex]; } }

        MenuItem[] MainMenuItems;
        MenuItem[] CampaignMenuItems;
        MenuItem[] ChapterSelectMenuItems;
        MenuItem[] EquipMenuItems;

        List<ArrowCard> EquipArrowCards;
        List<PassiveCard> EquipPassiveCards;
        List<SpellCard> EquipSpellCards;

        MenuItem[] nextMenuAfterAnamation = null;
        MenuItem[] previousMenuAfterAnimation = null;
        float menuAnimationTimeLeft = 0;

        Stack<List<Card>> CardItemStack = new Stack<List<Card>>();
        List<Card> CardsForItems
        {
            get
            {
                if (CardItemStack.Count == 0)
                {
                    return null;
                }
                else
                {
                    return CardItemStack.Peek();
                }
            }
        }
        Point cardPosition = new Point(375, 200);

        TextBox TextBox = new TextBox("");

        public CampState()
        {
            FireEmblemPortraitAnimation tbPortrait = new SorenPortrait(false);
            tbPortrait.IsSpeaking = false;
            tbPortrait.IsBlinking = false;
            TextBox.Portrait = tbPortrait;
            TextBox.Name = "Soren";
            TextBox.IsPortraitOnLeft = false;

            SorenAnimation.IsSpeaking = false;
            SorenAnimation.IsBlinking = true;

            MainMenuItems = new MenuItem[] {
                new MenuItem("Campaign", "March into the action and save the day!", new MenuAction(CampaignAction)),
                new MenuItem("Equip", "Equip yourself with the deadliest arrows,\n"
                                    + "choose two of your closest companions to\n"
                                    + "assist you, and strengthen yourself with\n"
                                    + "the most brutish of abilities.\n", new MenuAction(EquipAction)),                
                new MenuItem("Shop", "Find a selection of stock that rotates daily,\n"
                                   + "where you can spend your gold on exactly\n"
                                   + "whatever your heart desires.", new MenuAction(TodoAction)),
                new MenuItem("Harem", "Force the boys you have found to do sexual\n"
                                    + "acts so that you can take pictures of them\n"
                                    + "and sell them for rewards!", new MenuAction(TodoAction)),
                new MenuItem("Collection", "Look at all the pictures you have amassed\n"
                                         + "on your journeys from cards, puzzle pieces,\n"
                                         + "harem photographs and other sources.", new MenuAction(TodoAction))
            };

            CampaignMenuItems = new MenuItem[] {
                new MenuItem("Continue", "Continue from where you last left off.", new MenuAction(ContinueQuestAction)),
                new MenuItem("Start New Quest", "Start a new quest, abandoning any quest\n"
                                              + "that you have already started.", new MenuAction(StartNewQuestAction)),
            };

            CampaignMenuItems[0].IsAvailable = (PlayerStatus.GetStatus().CurrentQuest > 0);

            ChapterSelectMenuItems = new MenuItem[] {
                new MenuItem("Quest 1", "Birds of a Feather\n\n"
                                      + "Reyson is gone! You have to save him!", new MenuAction(StartQuest1Action)),
            };

            EquipMenuItems = new MenuItem[] {
                new MenuItem("Arrow", "You shoot these with every normal attack.\n"
                                    + "The damage you do depends on their strength.", new MenuAction(EquipArrowAction)),
                new MenuItem("Spell", "Charge your companions by typing flawlessly.\n"
                                      + "Then activate them for explosive effects!", new MenuAction(EquipSpell1Action)),
                new MenuItem("Spell", "Charge your companions by typing flawlessly.\n"
                                      + "Then activate them for explosive effects!", new MenuAction(EquipSpell2Action)),
                new MenuItem("Passive", "Equip these for a variety of benefits.", new MenuAction(EquipPassive1Action)),
                new MenuItem("Passive", "Equip these for a variety of benefits.", new MenuAction(EquipPassive2Action))
            };

            MenuStack = new Stack<MenuItem[]>();
            MenuStack.Push(MainMenuItems);

            SelectedItemIndex = 0;
            SelectedIndexStack = new Stack<int>();
        }

        public override void InitializeState()
        {            
            
        }

        void SwitchAheadToMenu(MenuItem[] menuItems)
        {
            SwitchAheadToMenu(menuItems, null);
        }

        void SwitchAheadToMenu(MenuItem[] menuItems, List<Card> cardItems)
        {
            nextMenuAfterAnamation = menuItems;
            menuAnimationTimeLeft = TotalMenuAnimationTime;
            TextBox.Text = "";

            CardItemStack.Push(cardItems);
            
        }

        void SwitchBackToMenu()
        {
            menuAnimationTimeLeft = TotalMenuAnimationTime;

            MenuItem[] currentMenu = MenuStack.Pop();
            previousMenuAfterAnimation = MenuStack.Peek(); // stealing the previous menu
            MenuStack.Push(currentMenu);
            TextBox.Text = "";
            CardItemStack.Pop();
        }

        void TodoAction()
        {
        }

        void CampaignAction()
        {
            SwitchAheadToMenu(CampaignMenuItems);
        }

        void ContinueQuestAction()
        {
            PlayerStatus status = PlayerStatus.GetStatus();
            ChangeStateAfterTick(new StoryState.StoryState(status.CurrentQuest, status.CurrentChapter), true);
        }

        void StartNewQuestAction()
        {
            SwitchAheadToMenu(ChapterSelectMenuItems);
        }

        void StartQuest1Action()
        {
            base.ChangeStateAfterTick(new StoryState.QuestStartState(new Quests.BirdsOfAFeatherQuest()), true);
        }

        void EquipAction()
        {
            Equipment equip = PlayerStatus.GetStatus().CurrentEquipment;
            List<Card> cardsForItems = new List<Card>() { equip.Arrow, equip.Spell1, equip.Spell2, equip.Passive1, equip.Passive2 };

            int arrowCardsOwned = CardManager.GetManager().GetArrowOnlyCount().Count(pair => (pair.Value > 0));
            EquipMenuItems[0].IsAvailable = (arrowCardsOwned > 0);
            

            int spellCardsOwned = CardManager.GetManager().GetSpellOnlyCount().Count(pair => (pair.Value > 0));            
            EquipMenuItems[1].IsAvailable = (spellCardsOwned > 0);
            EquipMenuItems[2].IsAvailable = (spellCardsOwned > 1);

            int passiveCardsOwned = CardManager.GetManager().GetPassiveOnlyCount().Count(pair => (pair.Value > 0));
            EquipMenuItems[3].IsAvailable = (passiveCardsOwned > 0);
            EquipMenuItems[4].IsAvailable = (passiveCardsOwned > 1);
            

            SwitchAheadToMenu(EquipMenuItems, cardsForItems);
        }

        void EquipArrowAction()
        {
            List<MenuItem> equipChoicesMenu = new List<MenuItem>();
            EquipArrowCards = new List<ArrowCard>();
            
            PlayerStatus status = PlayerStatus.GetStatus();

            string currentlyEquipped = (status.CurrentEquipment.Arrow == null) ? "Nothing" : status.CurrentEquipment.Arrow.Name;
            string description = string.Format("Choose an arrow to equip.\n\nCurrently equipped: {0}.", currentlyEquipped);

            Dictionary<ArrowCard, int> arrowCounts = CardManager.GetManager().GetArrowOnlyCount();
            foreach (var arrowCount in arrowCounts)
            {
                if (arrowCount.Value > 0)
                {
                    equipChoicesMenu.Add(new MenuItem(arrowCount.Key.Name, description, new MenuAction(DoEquipArrowAction)));
                    EquipArrowCards.Add(arrowCount.Key);
                }
            }

            List<Card> cardsForItems = new List<Card>(EquipArrowCards);
            SwitchAheadToMenu(equipChoicesMenu.ToArray(), cardsForItems);
        }

        void DoEquipArrowAction()
        {
            PlayerStatus status = PlayerStatus.GetStatus();
            status.CurrentEquipment.Arrow = EquipArrowCards[SelectedItemIndex];
            status.SaveToXml();
            SwitchBackToMenu();
            CardsForItems[0] = status.CurrentEquipment.Arrow;
        }

        void EquipSpell1Action()
        {
            List<MenuItem> equipChoicesMenu = new List<MenuItem>();
            EquipSpellCards = new List<SpellCard>();

            PlayerStatus status = PlayerStatus.GetStatus();

            string currentlyEquipped = (status.CurrentEquipment.Spell1 == null) ? "Nothing" : status.CurrentEquipment.Spell1.Name;
            string description = string.Format("Choose a spell to equip.\n\nCurrently equipped: {0}.", currentlyEquipped);

            Dictionary<SpellCard, int> SpellCounts = CardManager.GetManager().GetSpellOnlyCount();
            foreach (var spellCount in SpellCounts)
            {
                if (spellCount.Value > 0)
                {
                    if (spellCount.Value > 1 || PlayerStatus.GetStatus().CurrentEquipment.Spell2_ID != spellCount.Key.ID)
                    { // we either have at least two copies or we have one copy but the other spell isn't this one
                        equipChoicesMenu.Add(new MenuItem(spellCount.Key.Name, description, new MenuAction(DoEquipSpell1Action)));
                        EquipSpellCards.Add(spellCount.Key);
                    }
                }
            }

            List<Card> cardsForItems = new List<Card>(EquipSpellCards);
            SwitchAheadToMenu(equipChoicesMenu.ToArray(), cardsForItems);
        }

        void DoEquipSpell1Action()
        {
            PlayerStatus status = PlayerStatus.GetStatus();
            status.CurrentEquipment.Spell1 = EquipSpellCards[SelectedItemIndex];
            status.SaveToXml();
            SwitchBackToMenu();
            CardsForItems[1] = status.CurrentEquipment.Spell1;
        }

        void EquipSpell2Action()
        {
            List<MenuItem> equipChoicesMenu = new List<MenuItem>();
            EquipSpellCards = new List<SpellCard>();

            PlayerStatus status = PlayerStatus.GetStatus();

            string currentlyEquipped = (status.CurrentEquipment.Spell2 == null) ? "Nothing" : status.CurrentEquipment.Spell2.Name;
            string description = string.Format("Choose a spell to equip.\n\nCurrently equipped: {0}.", currentlyEquipped);

            Dictionary<SpellCard, int> SpellCounts = CardManager.GetManager().GetSpellOnlyCount();
            foreach (var spellCount in SpellCounts)
            {
                if (spellCount.Value > 0)
                {
                    if (spellCount.Value > 1 || PlayerStatus.GetStatus().CurrentEquipment.Spell1_ID != spellCount.Key.ID)
                    { // we either have at least two copies or we have one copy but the other spell isn't this one
                        equipChoicesMenu.Add(new MenuItem(spellCount.Key.Name, description, new MenuAction(DoEquipSpell2Action)));
                        EquipSpellCards.Add(spellCount.Key);
                    }
                }
            }

            List<Card> cardsForItems = new List<Card>(EquipSpellCards);
            SwitchAheadToMenu(equipChoicesMenu.ToArray(), cardsForItems);
        }

        void DoEquipSpell2Action()
        {
            PlayerStatus status = PlayerStatus.GetStatus();
            status.CurrentEquipment.Spell2 = EquipSpellCards[SelectedItemIndex];
            status.SaveToXml();
            SwitchBackToMenu();
            CardsForItems[2] = status.CurrentEquipment.Spell2;
        }

        void EquipPassive1Action()
        {
            List<MenuItem> equipChoicesMenu = new List<MenuItem>();
            EquipPassiveCards = new List<PassiveCard>();

            PlayerStatus status = PlayerStatus.GetStatus();

            string currentlyEquipped = (status.CurrentEquipment.Passive1 == null) ? "Nothing" : status.CurrentEquipment.Passive1.Name;
            string description = string.Format("Choose a passive to equip.\n\nCurrently equipped: {0}.", currentlyEquipped);

            Dictionary<PassiveCard, int> PassiveCounts = CardManager.GetManager().GetPassiveOnlyCount();
            foreach (var passiveCount in PassiveCounts)
            {
                if (passiveCount.Value > 0)
                {
                    if (passiveCount.Value > 1 || PlayerStatus.GetStatus().CurrentEquipment.Passive2_ID != passiveCount.Key.ID)
                    { // we either have at least two copies or we have one copy but the other Passive isn't this one
                        equipChoicesMenu.Add(new MenuItem(passiveCount.Key.Name, description, new MenuAction(DoEquipPassive1Action)));
                        EquipPassiveCards.Add(passiveCount.Key);
                    }
                }
            }

            List<Card> cardsForItems = new List<Card>(EquipPassiveCards);
            SwitchAheadToMenu(equipChoicesMenu.ToArray(), cardsForItems);
        }

        void DoEquipPassive1Action()
        {
            PlayerStatus status = PlayerStatus.GetStatus();
            status.CurrentEquipment.Passive1 = EquipPassiveCards[SelectedItemIndex];
            status.SaveToXml();
            SwitchBackToMenu();
            CardsForItems[3] = status.CurrentEquipment.Passive1;
        }

        void EquipPassive2Action()
        {
            List<MenuItem> equipChoicesMenu = new List<MenuItem>();
            EquipPassiveCards = new List<PassiveCard>();

            PlayerStatus status = PlayerStatus.GetStatus();

            string currentlyEquipped = (status.CurrentEquipment.Passive2 == null) ? "Nothing" : status.CurrentEquipment.Passive2.Name;
            string description = string.Format("Choose a passive to equip.\n\nCurrently equipped: {0}.", currentlyEquipped);

            Dictionary<PassiveCard, int> PassiveCounts = CardManager.GetManager().GetPassiveOnlyCount();
            foreach (var passiveCount in PassiveCounts)
            {
                if (passiveCount.Value > 0)
                {
                    if (passiveCount.Value > 1 || PlayerStatus.GetStatus().CurrentEquipment.Passive1_ID != passiveCount.Key.ID)
                    { // we either have at least two copies or we have one copy but the other Passive isn't this one
                        equipChoicesMenu.Add(new MenuItem(passiveCount.Key.Name, description, new MenuAction(DoEquipPassive2Action)));
                        EquipPassiveCards.Add(passiveCount.Key);
                    }
                }
            }

            List<Card> cardsForItems = new List<Card>(EquipPassiveCards);
            SwitchAheadToMenu(equipChoicesMenu.ToArray(), cardsForItems);
        }

        void DoEquipPassive2Action()
        {
            PlayerStatus status = PlayerStatus.GetStatus();
            status.CurrentEquipment.Passive2 = EquipPassiveCards[SelectedItemIndex];
            status.SaveToXml();
            SwitchBackToMenu();
            CardsForItems[4] = status.CurrentEquipment.Passive2;
        }

        public override void Draw(General.Camera camera)
        {
            BackgroundAnimation.Draw(camera, BackgroundRectangle);

            /* Animation moving */

            float animationOffsetX = 0;
            if (menuAnimationTimeLeft > 0)
            {
                animationOffsetX = buttons[0].Right * (1 - menuAnimationTimeLeft / TotalMenuAnimationTime);
                if (nextMenuAfterAnamation != null)
                {
                    animationOffsetX *= -1;
                }
            }

            /* Draw Buttons */

            for (int i = 0; i < CurrentItems.Length; i++)
            {
                Rectangle button = buttons[i];
                button.Offset((int)animationOffsetX, 0);

                Color textColor;
                if (!CurrentItems[i].IsAvailable)
                {
                    InactiveButtonAnimation.Draw(camera, button);
                    textColor = Color.Gray;
                }
                else if (i == SelectedItemIndex)
                {
                    SelectedButtonAnimation.Draw(camera, button);
                    textColor = Color.Yellow;
                }
                else
                {
                    ButtonAnimation.Draw(camera, button);
                    textColor = Color.White;
                }
                camera.MakeText(CurrentItems[i].Name)
                    .WithCenteredPosition(button.Center)
                    .WithFont(Camera.TextDrawer.TimesNewRomanBigFont)
                    .WithColor(textColor)
                    .Draw();
            }

            /* Draw upcoming menu */

            if (menuAnimationTimeLeft > 0 && previousMenuAfterAnimation != null)
            {
                for (int i = 0; i < previousMenuAfterAnimation.Length; i++)
                {
                    Rectangle button = buttons[i];
                    button.Offset((int)animationOffsetX - 254, 0);

                    Color textColor;
                    if (!previousMenuAfterAnimation[i].IsAvailable)
                    {
                        InactiveButtonAnimation.Draw(camera, button);
                        textColor = Color.Gray;
                    }
                    else if (i == SelectedIndexStack.Peek())
                    {
                        SelectedButtonAnimation.Draw(camera, button);
                        textColor = Color.Yellow;
                    }
                    else
                    {
                        ButtonAnimation.Draw(camera, button);
                        textColor = Color.White;
                    }
                    camera.MakeText(previousMenuAfterAnimation[i].Name)
                        .WithCenteredPosition(button.Center)
                        .WithFont(Camera.TextDrawer.TimesNewRomanBigFont)
                        .WithColor(textColor)
                        .Draw();
                }
            }

            /* Soren */
            
            SorenAnimation.DrawWithBottomLeft(camera, SorenBottomLeft);

            /* Card */
            if (menuAnimationTimeLeft <= 0 && CardsForItems != null && CardsForItems[SelectedItemIndex] != null)
            {
                CardsForItems[SelectedItemIndex].Draw(camera, cardPosition);
            }

            /* TextBox */

            if (menuAnimationTimeLeft <= 0)
            {
                TextBox.Text = CurrentItems[SelectedItemIndex].Description;
            }
            TextBox.Draw(camera);

            //new Cards.SpellCard(new GameState.PlayerSpells.ElfireSpell()).Draw(camera, new Point(375,200));
        }

        public override void Tick(float dt)
        {
            TextBox.Tick(dt);
            SorenAnimation.Advance(dt);

            if (menuAnimationTimeLeft > 0)
            {
                menuAnimationTimeLeft -= dt;

                if (menuAnimationTimeLeft <= 0)
                {
                    if (nextMenuAfterAnamation != null)
                    {
                        MenuStack.Push(nextMenuAfterAnamation);
                        nextMenuAfterAnamation = null;

                        SelectedIndexStack.Push(SelectedItemIndex);

                        SelectedItemIndex = 0;
                        for (int i = 0; i < CurrentItems.Length; i++)
                        {
                            if (CurrentItems[i].IsAvailable)
                            {
                                SelectedItemIndex = i;
                                break;
                            }
                        }
                        
                    }
                    else if (previousMenuAfterAnimation != null)
                    {
                        MenuStack.Pop();
                        previousMenuAfterAnimation = null;
                        SelectedItemIndex = SelectedIndexStack.Pop();
                    }
                }
            }

            base.Tick(dt);
        }

        public override void HandleInput(General.InputInfo inputInfo)
        {
            if (menuAnimationTimeLeft > 0)
            {
                return;
            }

            if (inputInfo.IsKeyJustPressed(GameKey.Up) && SelectedItemIndex != 0)
            {
                for (int i = SelectedItemIndex - 1; i >= 0; i--)
                {
                    if (CurrentItems[i].IsAvailable)
                    {
                        SelectedItemIndex = i;
                        break;
                    }
                }
            }
            else if (inputInfo.IsKeyJustPressed(GameKey.Down) && SelectedItemIndex != CurrentItems.Length - 1)
            {
                for (int i = SelectedItemIndex + 1; i < CurrentItems.Length; i++)
                {
                    if (CurrentItems[i].IsAvailable)
                    {
                        SelectedItemIndex = i;
                        break;
                    }
                }
            }
            else if (inputInfo.IsKeyJustPressed(GameKey.Left))
            {
                if (MenuStack.Count > 1)
                {
                    SwitchBackToMenu();
                }
            }
            else if (inputInfo.IsKeyJustPressed(GameKey.Escape))
            {
                if (MenuStack.Count > 1)
                {
                    SwitchBackToMenu();
                }
                else
                {
                    TypingGame.Game().Exit();
                }
            }

            if (inputInfo.IsKeyJustPressed(GameKey.Use))
            {
                SelectedItem.Action();
            }

        }

        delegate void MenuAction();
        private class MenuItem
        {
            public string Name { get; set; }
            public string Description { get; set; }
            public MenuAction Action { get; set; }
            public bool IsAvailable { get; set; }

            public MenuItem(string name, string description, MenuAction action) : this(name, description, action, true) { }
            public MenuItem(string name, string description, MenuAction action, bool isAvailable)
            {
                Name = name;
                Description = description;
                Action = action;
                IsAvailable = isAvailable;
            }
        }
    }
}
